﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;

namespace Master
{
    /**
     * Takes care of the traffic lights on intersection and puts one traffic light on green at a time.
     * 
     * @Creator: T.T. Dusseldorp
     * @Changes made by:
     *      - A.J. Janssen
     */
    class SimpleTrafficLightStrategy : iTrafficLightStrategy
    {
        /*************
         * VARIABLES *
         *************/
        private Thread strategyThread;
        private TrafficMarshal trafficMarshal = new BasicTrafficMarshal();
        private Dictionary<Side, List<Lane>> laneDictionary;
        private TrafficLightDetails trafficLightDetails;

        /********************
         * PUBLIC FUNCTIONS *
         ********************/
        /**
         * Gets all the trafficlights from all the lanes connected to the intersection and saves the lanes in list of lanes based on orientation.
         * Sets the time spend on green, yellow and red acording to the trafficlightDetails.
         * Creates and starts the TwoWayTrafficlightStrategy thread.
         */
        public void start(InterSection interSection, TrafficLightDetails trafficLightDetails)
        {
            Dictionary<Side, List<Road>> roadDictionary = interSection.getRoadDictionary();
            this.laneDictionary = new Dictionary<Side, List<Lane>>();
            foreach (Side side in roadDictionary.Keys)
            {
                List<Lane> laneList = new List<Lane>();
                foreach (Road road in roadDictionary[side]) 
                    foreach (Lane lane in road.getLanes())
                        if (lane.hasTrafficLight()) 
                            laneList.Add(lane);
                this.laneDictionary.Add(side, laneList);
            }
            if (interSection.isThreeLaneIntersection())
                trafficMarshal = new ThreeLaneTrafficMarshal();
            this.trafficLightDetails = trafficLightDetails;
            strategyThread = new Thread(handleTraffic);
            strategyThread.Start();
            
        }

        /**
         * Stops the thread.
         */
        public void stop()
        {
            strategyThread.Abort();
        }

        // can be used on all intersections
        public Boolean canBeUsedOnInterSection(InterSection interSection)
        {
            return true;
        }

        // gets the current TrafficMarshal
        public TrafficMarshal getTrafficMarshal()
        {
            return trafficMarshal;
        }

        /*********************
         * PRIVATE FUNCTIONS *
         *********************/
        private void handleTraffic()
        {
            try
            {
                Thread.Sleep(5000);
                while (true)
                {
                    foreach (Side side in laneDictionary.Keys)
                    {
                        foreach (Lane lane in laneDictionary[side])
                            setStatus(lane, TrafficLightStatus.GREEN);
                        Thread.Sleep(trafficLightDetails.getGreenTime());
                        foreach (Lane lane in laneDictionary[side])
                            setStatus(lane, TrafficLightStatus.ORANGE);
                        Thread.Sleep(trafficLightDetails.getOrangeTime());
                        foreach (Lane lane in laneDictionary[side])
                            setStatus(lane, TrafficLightStatus.RED);
                        Thread.Sleep(trafficLightDetails.getRedTime());
                    }
                }
            }
            catch (ThreadAbortException e)
            {
                Trace.WriteLine("Thread was aborted by: " + e.GetType());
                foreach (Side side in laneDictionary.Keys)
                    foreach (Lane lane in laneDictionary[side])
                        setStatus(lane, TrafficLightStatus.RED);
                return;
            }
        }

        private void setStatus(Lane lane, TrafficLightStatus newStatus)
        {
            lane.Dispatcher.Invoke(
                new Action(delegate() { lane.trafficLight.SetValue(TrafficLight.statusProperty, newStatus); })
            );
        }
    }
}
